#include <iostream>
#include <thread>
#include <chrono>

#include "server.h"
#include "hv/hlog.h"
#include "hv/hloop.h"
#include "hv/hsocket.h"

static uint8_t  g_recving_hrd = 1;
static int g_body_len = 0;

static void on_close(hio_t *io) {
    LOGW("[ S ] connection closed, fd: %d, error: %s", hio_fd(io), hio_error(io));
}

static void on_recv(hio_t *io, void *buf, int readbytes) {
    if (g_recving_hrd) {
        g_body_len = *((int *)buf);
        if (g_body_len <= 10 * 1024 * 1024) {
            buf = realloc(buf, g_body_len);
            hio_set_readbuf(io, buf, g_body_len);

            LOGI("[ S ] recv header. fd: %d, readbytes: %d, body length: %d", hio_fd(io), readbytes, g_body_len);
            g_recving_hrd = 0;
        } else {
            LOGE("[ S ] too large body. fd: %d, readbytes: %d, body length: %d", hio_fd(io), readbytes, g_body_len);
            //hio_close(io);
        }
    } else {
        if (readbytes >= g_body_len) {
            LOGI("[ S ] recv body. fd: %d, readbytes: %d", hio_fd(io), readbytes);
            g_recving_hrd = 1;
            free(buf);
        } else {
            LOGE("[ S ] recv wrong body. fd: %d, readbytes: %d, body length: %d", hio_fd(io), readbytes, g_body_len);
        }
    }
}

static void on_accept(hio_t *io) {
    char localaddrstr[SOCKADDR_STRLEN] = {0};
    char peeraddrstr[SOCKADDR_STRLEN] = {0};

    LOGI("[ S ] accept connection, fd: %d [%s] <= [%s]", hio_fd(io),
        SOCKADDR_STR(hio_localaddr(io), localaddrstr),
        SOCKADDR_STR(hio_peeraddr(io), peeraddrstr)
    );

    void *buf = malloc(sizeof(int));

    hio_setcb_close(io, on_close);
    hio_setcb_read(io, on_recv);
    hio_set_readbuf(io, buf, sizeof(int));
    hio_read(io);
}

void smain(uint16_t port) {
    hloop_t *loop = hloop_new(0);

    hio_t *sio = create_tcp_server(loop, "0.0.0.0", port, on_accept);
    if (sio == NULL) {
        LOGE("[ S ] Failed create_tcp_server.");
    } else {
        LOGI("[ S ] listen on port: %d, fd: %d", port, hio_fd(sio));
        hloop_run(loop);
    }

    hloop_free(&loop);

    LOGI("[ S ] Exit.");
}
